package com.hyt.it.ogt.ks.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hyt.common.utils.exception.BusinessException;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.ks.enums.EsCandidateOperationTrackLogCode;
import com.hyt.it.ogt.ks.enums.FaceState;
import com.hyt.it.ogt.ks.enums.log.AdminOperatorLogType;
import com.hyt.it.ogt.ks.enums.log.ApplyCheckState;
import com.hyt.it.ogt.ks.enums.log.CandidateOperatorLogType;
import com.hyt.it.ogt.ks.enums.log.LogEventType;
import com.hyt.it.ogt.ks.es.CandidateOperationTrackLogDTO;
import com.hyt.it.ogt.ks.mapper.CandidateLogOtherMapper;
import com.hyt.it.ogt.ks.model.entity.CandidateLogOther;
import com.hyt.it.ogt.ks.model.entity.ExamCandidateStatus;
import com.hyt.it.ogt.ks.model.vo.CandidateLogBeginTimeVO;
import com.hyt.it.ogt.ks.model.vo.log.AnswerVO;
import com.hyt.it.ogt.ks.model.vo.CandidateLogVo;
import com.hyt.it.ogt.ks.service.IApplyCheckService;
import com.hyt.it.ogt.ks.service.ICandidateLogOtherService;
import com.hyt.it.ogt.ks.service.IExamCandidateStatusService;
import com.hyt.it.ogt.ks.service.es.IEsAndDbService;
import com.hyt.it.ogt.ks.util.LocalDateTimeUtils;
import com.hyt.it.ogt.opertaion.track.model.OtherLogVO;
import io.seata.common.util.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 轨迹表-其他轨迹表 服务实现类
 * </p>
 *
 * @author liteng
 * @since 2022-11-22
 */
@Service
@Slf4j
public class CandidateLogOtherServiceImpl extends BaseServiceImpl<CandidateLogOtherMapper, CandidateLogOther> implements ICandidateLogOtherService {
    @Resource
    private IApplyCheckService applyCheckService;
    @Resource
    private IExamCandidateStatusService examCandidateStatusService;
    @Resource
    private IEsAndDbService esAndDbService;

    @Override
    public Boolean saveOtherLog(List<OtherLogVO> otherLogVOList) {
        try {
            super.saveBatch(otherLogVOList.stream().map(vo-> CandidateLogOther.builder()
                    .id(UUIDUtils.randomUUID())
                    .examId(vo.getExamId())
                    .candidateId(vo.getCandidateId())
                    .eventType(vo.getEventType())
                    .operateType(vo.getOperateType())
                    .operateContent(vo.getOperateContent())
                    .operateUser(vo.getOperateUser())
                    .beginTime(vo.getBeginTime().contains(".") ? LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSSSSS))
                            : LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSS)))
                    .build()).collect(Collectors.toList()));
            //异步同步ES
            esAndDbService.asyncSaveCandidateOperationTrackLog(otherLogVOList.stream().map(vo -> CandidateOperationTrackLogDTO.builder()
                            .type(EsCandidateOperationTrackLogCode.OTHER.getCode())
                            .examId(vo.getExamId())
                            .candidateId(vo.getCandidateId())
                            .eventType(vo.getEventType())
                            .operateType(vo.getOperateType())
                            .operateContent(vo.getOperateContent())
                            .operateUser(vo.getOperateUser())
                            .beginTime(vo.getBeginTime().contains(".") ? LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSSSSS))
                                    : LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSS)))
                            .build()).collect(Collectors.toList()));
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public List<CandidateLogBeginTimeVO> getCandidateLogBeginOtherTime(String examId, String operatorType) {
        return baseMapper.getCandidateLogBeginOtherTime(examId, operatorType);
    }

    @Override
    public void sendApplyCheckResult2StudentByLogOtherId(String id) {
        CandidateLogOther candidateLogOther = getById(id);
        if (Objects.isNull(candidateLogOther)) {
            throw new RuntimeException(String.format("轨迹%s不存在", id));
        }
        if (Objects.equals(AdminOperatorLogType.ID_CHECK_PASSED.getCode(), candidateLogOther.getOperateType())) {
            applyCheckService.sendApplyCheckResult2Student(candidateLogOther.getExamId(),
                    candidateLogOther.getCandidateId(),
                    LogEventType.OPERATOR_LOG.getCode(),
                    CandidateOperatorLogType.ID_FACE_SKIP_APPLY.getCode());
        } else if (Objects.equals(AdminOperatorLogType.DEVICE_CHECK_PASSED.getCode(), candidateLogOther.getOperateType())) {
            applyCheckService.sendApplyCheckResult2Student(candidateLogOther.getExamId(),
                    candidateLogOther.getCandidateId(),
                    LogEventType.OPERATOR_LOG.getCode(),
                    CandidateOperatorLogType.DEVICE_CHECK_SKIP_APPLY.getCode());
        }
    }

    @Override
    public List<CandidateLogOther> queryAnswerOtherLogByPage(String examId, String candidateId, Integer eventType, Integer logType, Integer offset, Integer limit) {
        return baseMapper.queryAnswerOtherLogByPage(examId, candidateId, eventType, logType, offset, limit);
    }

    @Override
    public void saveCandidateOtherStatus(List<OtherLogVO> otherLogVOList) {
        List<ExamCandidateStatus> examCandidateStatusList = new ArrayList<>();
        try {
            otherLogVOList.forEach(vo -> {
                LocalDateTime beginTime = vo.getBeginTime().contains(".") ? LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSSSSS))
                        : LocalDateTime.parse(vo.getBeginTime(), DateTimeFormatter.ofPattern(LocalDateTimeUtils.YYYYMMDDHHMMSS));
                switch (vo.getOperateType()) {
                    case 301://登录
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .firstLoginTime(beginTime)
                                .lastLoginTime(beginTime)
                                .loginNum(1).build());
                        break;
                    case 209://二次及以上登录
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .lastLoginTime(beginTime)
                                .loginNum(1).build());
                        break;
                    case 205://考试中断
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .interruptTime(beginTime).build());
                        break;
                    case 307:
                    case 402:
                    case 211://设备检测
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .deviceCheckNum(1).build());
                        break;
                    case 203://主监控中断
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .firstInterruptNum(1).build());
                        break;
                    case 204://移动监控中断
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .secondInterruptNum(1).build());
                        break;
                    case 202://视频标记
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .videoMarkNum(1).build());
                        break;
                    case 201://切屏
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .maxChangeScreen(JSONObject.parseObject(vo.getOperateContent(), AnswerVO.class).getTakeTime()).build());
                        break;
                    case 309:// 人脸核身成功
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .authenticationTime(1)
                                .authenticationState(FaceState.SUCCESS.getCode())
                                .lastAuthenticationDate(beginTime).build());
                        break;
                    case 207://人脸核身失败
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .authenticationTime(1)
                                .authenticationState(FaceState.FAILD.getCode())
                                .lastAuthenticationDate(beginTime).build());
                        break;
                    case 401:// 人脸核身
                             // applyResult = 1 成功 -》 3人工审核-通过
                             // applyResult = 2 失败 -》 3人工审核-不通过
                        examCandidateStatusList.add(ExamCandidateStatus.builder().examId(vo.getExamId()).candidateId(vo.getCandidateId())
                                .authenticationState((Objects.equals(ApplyCheckState.PASSED.getCode(), JSON.parseObject(vo.getOperateContent(), CandidateLogOther.OperateContent.class).getApplyResult())
                                        ? ApplyCheckState.PASSED.getCode() : ApplyCheckState.NO_PASSED.getCode())).build());
                        break;
                    default:break;
                }
            });
        } catch (Exception e) {
            log.error("考生过程状态变化解析异常", e);
        }
        if(CollectionUtils.isNotEmpty(examCandidateStatusList)) {
            examCandidateStatusService.saveCandidateStatus(examCandidateStatusList);
        }
    }

    @Override
    public void syncOtherByExamId(String examId) {
        Integer count = baseMapper.getCountByExamId(examId);
        if (count == 0) {
            return;
        }
        long pageTotal;
        long pageSize = 200;
        if (count % pageSize == 0) {
            pageTotal = count / pageSize;
        } else {
            pageTotal = count / pageSize + 1;
        }
        for (int i = 1; i <= pageTotal; i++) {
            long startIndex = (i - 1) * pageSize;
            List<CandidateLogOther> otherLogVOList = baseMapper.findListByExamId(examId, startIndex, pageSize);
            if (CollectionUtils.isNotEmpty(otherLogVOList)) {
                esAndDbService.saveCandidateOperationTrackLog(otherLogVOList.stream().map(vo -> CandidateOperationTrackLogDTO.builder()
                        .type(EsCandidateOperationTrackLogCode.OTHER.getCode())
                        .examId(vo.getExamId())
                        .candidateId(vo.getCandidateId())
                        .eventType(vo.getEventType())
                        .operateType(vo.getOperateType())
                        .operateContent(vo.getOperateContent())
                        .operateUser(vo.getOperateUser())
                        .beginTime(vo.getBeginTime())
                        .build()).collect(Collectors.toList()));
            }
        }
    }

    @Override
    public void syncOtherAll() {
        Integer count = baseMapper.getCountByAll();
        if (count == 0) {
            return;
        }
        long pageTotal;
        long pageSize = 200;
        if (count % pageSize == 0) {
            pageTotal = count / pageSize;
        } else {
            pageTotal = count / pageSize + 1;
        }
        for (int i = 1; i <= pageTotal; i++) {
            long startIndex = (i - 1) * pageSize;
            List<CandidateLogOther> otherLogVOList = baseMapper.findListByAll(startIndex, pageSize);
            if (CollectionUtils.isNotEmpty(otherLogVOList)) {
                esAndDbService.saveCandidateOperationTrackLog(otherLogVOList.stream().map(vo -> CandidateOperationTrackLogDTO.builder()
                        .type(EsCandidateOperationTrackLogCode.OTHER.getCode())
                        .examId(vo.getExamId())
                        .candidateId(vo.getCandidateId())
                        .eventType(vo.getEventType())
                        .operateType(vo.getOperateType())
                        .operateContent(vo.getOperateContent())
                        .operateUser(vo.getOperateUser())
                        .beginTime(vo.getBeginTime())
                        .build()).collect(Collectors.toList()));
            }
        }
    }

    @Override
    public List<CandidateLogVo> getMaxTimeByOperateType(String examId, String operatorType) {
        return baseMapper.getMaxTimeByOperateType(examId, operatorType);
    }

    @Override
    public List<CandidateLogVo> getMaxAndMinTimeByOperateType(String examId, String operatorType){
        return baseMapper.getMaxAndMinTimeByOperateType(examId, operatorType);
    }

}
